﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Security.Cryptography.X509Certificates;
using System.Net;
using System.Net.Security;
using System.ComponentModel;
using System.IO;
using System.Collections.Specialized;

namespace UtilityLibrary.Http
{
	public class HttpClient
	{
		#region  --属性--

		private Encoding _encoding;
		/// <summary>
		/// 获取编码格式
		/// </summary>
		public Encoding Encoding
		{
			get { return _encoding; }
		}

		private Int32 _timeout;
		/// <summary>
		/// 超时时间
		/// </summary>
		public Int32 Timeout
		{
			set
			{
				_timeout = value;
			}
		}

		private ICertModel _certModel;
		/// <summary>
		/// 证书模块
		/// </summary>
		public ICertModel CertModel { get { return _certModel; } }

		private ICookieModel _cookieModel;
		/// <summary>
		/// 处理Cookie模块
		/// </summary>
		public ICookieModel CookieModel { get { return _cookieModel; } }

		private IProcessRecordModel _record;
		/// <summary>
		/// 记录请求过程的模块
		/// </summary>
		public IProcessRecordModel Record { get; set; }

		#endregion

		#region  --构造函数--

		/// <summary>
		/// 构造函数
		/// </summary>
		/// <param name="encoding">请求过程中所使用的编码类型</param>
		public HttpClient(Encoding encoding)
		{
			//初始化Cookie容器
			_encoding = encoding;
			_timeout = 300000;
			_cookieModel = new CookieContainerModel();
		}

		/// <summary>
		/// 构造函数
		/// </summary>
		/// <param name="encoding">请求过程中所使用的编码类型</param>
		/// <param name="thumbprint">请求过程中使用证书的指纹</param>
		public HttpClient(Encoding encoding, String thumbprint)
			: this(encoding)
		{
			if (!String.IsNullOrEmpty(thumbprint)) _certModel = new ThumbprintCertModel(thumbprint);
		}

		/// <summary>
		/// 构造函数
		/// </summary>
		/// <param name="encoding">请求过程中所使用的编码类型</param>
		/// <param name="thumbprint">请求过程中使用的证书模块</param>
		public HttpClient(Encoding encoding, ICertModel certModel)
			: this(encoding)
		{
			if (certModel != null) _certModel = certModel;
		}

		/// <summary>
		/// 构造函数
		/// </summary>
		/// <param name="encoding">请求过程中所使用的编码类型</param>
		/// <param name="cookieModel">请求过程中处理Cookie的模块</param>
		public HttpClient(Encoding encoding, ICookieModel cookieModel)
			: this(encoding)
		{
			if (cookieModel != null) _cookieModel = cookieModel;
		}

		/// <summary>
		/// 构造函数
		/// </summary>
		/// <param name="encoding">请求过程中所使用的编码类型</param>
		/// <param name="cookieModel">请求过程中处理Cookie的模块</param>
		/// <param name="thumbprint">请求过程中使用证书的指纹</param>
		public HttpClient(Encoding encoding, ICookieModel cookieModel, String thumbprint)
			: this(encoding, cookieModel)
		{
			if (!String.IsNullOrEmpty(thumbprint)) _certModel = new ThumbprintCertModel(thumbprint);
		}

		/// <summary>
		/// 构造函数
		/// </summary>
		/// <param name="encoding">请求过程中所使用的编码类型</param>
		/// <param name="cookieModel">请求过程中处理Cookie的模块</param>
		/// <param name="thumbprint">请求过程中使用的证书模块</param>
		public HttpClient(Encoding encoding, ICookieModel cookieModel, ICertModel certModel)
			: this(encoding, cookieModel)
		{
			if (certModel != null) _certModel = certModel;
		}

		/// <summary>
		/// 构造函数
		/// </summary>
		/// <param name="encoding">请求过程中所使用的编码类型</param>
		/// <param name="record">记录请求过程的模块</param>
		public HttpClient(Encoding encoding, IProcessRecordModel record)
			: this(encoding)
		{
			if (record != null) _record = record;
		}

		/// <summary>
		/// 构造函数
		/// </summary>
		/// <param name="encoding">请求过程中所使用的编码类型</param>
		/// <param name="cookieModel">请求过程中处理Cookie的模块</param>
		/// <param name="record">记录请求过程的模块</param>
		public HttpClient(Encoding encoding, ICookieModel cookieModel, IProcessRecordModel record)
			: this(encoding, cookieModel)
		{
			if (record != null) _record = record;
		}

		/// <summary>
		/// 构造函数
		/// </summary>
		/// <param name="encoding">请求过程中所使用的编码类型</param>
		/// <param name="cookieModel">请求过程中处理Cookie的模块</param>
		/// <param name="thumbprint">请求过程中使用证书的指纹</param>
		/// <param name="record">记录请求过程的模块</param>
		public HttpClient(Encoding encoding, ICookieModel cookieModel, String thumbprint, IProcessRecordModel record)
			: this(encoding, cookieModel, thumbprint)
		{
			if (record != null) _record = record;
		}

		/// <summary>
		/// 构造函数
		/// </summary>
		/// <param name="encoding">请求过程中所使用的编码类型</param>
		/// <param name="cookieModel">请求过程中处理Cookie的模块</param>
		/// <param name="certModel">请求过程中使用的证书模块</param>
		/// <param name="record">记录请求过程的模块</param>
		public HttpClient(Encoding encoding, ICookieModel cookieModel, ICertModel certModel, IProcessRecordModel record)
			: this(encoding, cookieModel, certModel)
		{
			if (record != null) _record = record;
		}

		#endregion

		#region  --编码转换--

		/// <summary>
		/// 中文编码转换
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		public String Encode(String value)
		{
			return HttpUtility.UrlEncode(value, Encoding);
		}

		/// <summary>
		/// 编码转中文
		/// </summary>
		/// <param name="value"></param>
		/// <param name="encoding"></param>
		/// <returns></returns>
		public String Decode(String value)
		{
			return HttpUtility.UrlDecode(value, Encoding);
		}

		#endregion

		#region   --HTTP请求过程相关方法--

		/// <summary>
		/// GET方式获得响应
		/// </summary>
		/// <param name="request">请求对象</param>
		/// <returns>响应对象</returns>
		public HttpWebResponse Get(HttpWebRequest request)
		{
			//设置安全请求模式
			ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;

			//添加cookie
			_cookieModel.SetCookies(request);

			//添加证书
			if(_certModel != null) _certModel.SetCert(request);

			//设置请求方式
			request.Method = "GET";
			request.Timeout = _timeout;

			//获得响应
			HttpWebResponse response = (HttpWebResponse)request.GetResponse();
			_cookieModel.GetCookies(response);
			if (_record != null) _record.Record(request, response);

			return response;
		}

		/// <summary>
		/// GET方式获得响应
		/// </summary>
		/// <param name="url">请求地址</param>
		/// <returns>响应对象</returns>
		public HttpWebResponse Get(String url)
		{
			return Get(DefaultRequest.FromString(url));
		}

		/// <summary>
		/// GET方式获得响应流对象
		/// </summary>
		/// <param name="request">请求对象</param>
		/// <returns>内存流</returns>
		public MemoryStream GetStream(HttpWebRequest request)
		{
			return StreamFromResponse(Get(request));
		}

		/// <summary>
		/// GET方式获得响应流对象
		/// </summary>
		/// <param name="url">请求地址</param>
		/// <returns>内存流</returns>
		public MemoryStream GetStream(String url)
		{
			return StreamFromResponse(Get(url));
		}

		/// <summary>
		/// GET方式获得响应流对象
		/// </summary>
		/// <param name="request">请求对象</param>
		/// <param name="fileName">文件路径</param>
		public void GetSaveAs(HttpWebRequest request, String fileName)
		{
			SaveAsFromResponse(Get(request), fileName);
		}

		/// <summary>
		/// GET方式获得响应流对象
		/// </summary>
		/// <param name="url">请求地址</param>
		/// <param name="fileName">文件路径</param>
		public void GetSaveAs(String url, String fileName)
		{
			SaveAsFromResponse(Get(url), fileName);
		}

		/// <summary>
		/// GET方式获得响应流对象
		/// </summary>
		/// <param name="request">请求对象</param>
		/// <returns>响应字符串</returns>
		public String GetString(HttpWebRequest request)
		{
			return StringFromResponse(Get(request), _encoding);
		}

		/// <summary>
		/// GET方式获得响应流对象
		/// </summary>
		/// <param name="url">请求地址</param>
		/// <returns>响应字符串</returns>
		public String GetString(String url)
		{
			return StringFromResponse(Get(url), _encoding);
		}

		/// <summary>
		/// GET方式获得响应流对象
		/// </summary>
		/// <param name="request">请求对象</param>
		/// <returns>响应字符串</returns>
		public HtmlContext GetHtmlContext(HttpWebRequest request)
		{
			return new HtmlContext(StringFromResponse(Get(request), _encoding));
		}

		/// <summary>
		/// GET方式获得响应流对象
		/// </summary>
		/// <param name="url">请求地址</param>
		/// <returns>响应字符串</returns>
		public HtmlContext GetHtmlContext(String url)
		{
			return new HtmlContext(StringFromResponse(Get(url), _encoding));
		}

		/// <summary>
		/// POST方式获得响应
		/// </summary>
		/// <param name="request">请求对象</param>
		/// <param name="param">参数字符串</param>
		/// <returns>响应对象</returns>
		public HttpWebResponse Post(HttpWebRequest request, String param)
		{
			//设置安全请求模式
			ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;

			//添加cookie
			_cookieModel.SetCookies(request);

			//添加证书
			if (_certModel != null) _certModel.SetCert(request);

			//设置请求方式
			request.Method = "POST";
			request.Timeout = _timeout;
			if (!String.IsNullOrEmpty(param)) SetPostData(request, param);

			//获得响应并设置Cookies
			HttpWebResponse response = (HttpWebResponse)request.GetResponse();
			_cookieModel.GetCookies(response);
			if (_record != null) _record.Record(request, response);

			return response;
		}

		/// <summary>
		/// POST方式获得响应
		/// </summary>
		/// <param name="url">请求地址</param>
		/// <param name="param">参数字符串</param>
		/// <returns>响应对象</returns>
		public HttpWebResponse Post(String url, String param)
		{
			return Post(DefaultRequest.FromString(url), param);
		}

		/// <summary>
		/// POST方式获得响应
		/// </summary>
		/// <param name="request">请求对象</param>
		/// <param name="collection">参数集合对象</param>
		/// <returns>响应对象</returns>
		public HttpWebResponse Post(HttpWebRequest request, NameValueCollection collection)
		{
			return Post(request, NameValueCollectionToString(collection));
		}

		/// <summary>
		/// POST方式获得响应
		/// </summary>
		/// <param name="url">请求地址</param>
		/// <param name="collection">参数集合对象</param>
		/// <returns>响应对象</returns>
		public HttpWebResponse Post(String url, NameValueCollection collection)
		{
			return Post(url, NameValueCollectionToString(collection));
		}

		/// <summary>
		/// POST方式获得响应流
		/// </summary>
		/// <param name="request">请求对象</param>
		/// <param name="param">参数字符串</param>
		/// <returns>内存流</returns>
		public MemoryStream PostStream(HttpWebRequest request, String param)
		{
			return StreamFromResponse(Post(request, param));
		}

		/// <summary>
		/// POST方式获得响应流
		/// </summary>
		/// <param name="url">请求地址</param>
		/// <param name="param">参数字符串</param>
		/// <returns>内存流</returns>
		public MemoryStream PostStream(String url, String param)
		{
			return StreamFromResponse(Post(url, param));
		}

		/// <summary>
		/// POST方式获得响应流
		/// </summary>
		/// <param name="request">请求对象</param>
		/// <param name="collection">参数集合对象</param>
		/// <returns>内存流</returns>
		public MemoryStream PostStream(HttpWebRequest request, NameValueCollection collection)
		{
			return StreamFromResponse(Post(request, collection));
		}

		/// <summary>
		/// POST方式获得响应流
		/// </summary>
		/// <param name="url">请求地址</param>
		/// <param name="collection">参数集合对象</param>
		/// <returns>内存流</returns>
		public MemoryStream PostStream(String url, NameValueCollection collection)
		{
			return StreamFromResponse(Post(url, collection));
		}

		/// <summary>
		/// POST方式获得响应流
		/// </summary>
		/// <param name="request">请求对象</param>
		/// <param name="param">参数字符串</param>
		/// <returns>内存流</returns>
		public void PostSaveAs(HttpWebRequest request, String param, String fileName)
		{
			SaveAsFromResponse(Post(request, param), fileName);
		}

		/// <summary>
		/// POST方式获得响应流
		/// </summary>
		/// <param name="url">请求地址</param>
		/// <param name="param">参数字符串</param>
		/// <returns>内存流</returns>
		public void PostSaveAs(String url, String param, String fileName)
		{
			SaveAsFromResponse(Post(url, param), fileName);
		}

		/// <summary>
		/// POST方式获得响应流
		/// </summary>
		/// <param name="request">请求对象</param>
		/// <param name="collection">参数集合对象</param>
		/// <returns>内存流</returns>
		public void PostSaveAs(HttpWebRequest request, NameValueCollection collection, String fileName)
		{
			SaveAsFromResponse(Post(request, collection), fileName);
		}

		/// <summary>
		/// POST方式获得响应流
		/// </summary>
		/// <param name="url">请求地址</param>
		/// <param name="collection">参数集合对象</param>
		/// <returns>内存流</returns>
		public void PostSaveAs(String url, NameValueCollection collection, String fileName)
		{
			SaveAsFromResponse(Post(url, collection), fileName);
		}

		/// <summary>
		/// POST方式获得响应流
		/// </summary>
		/// <param name="request">请求对象</param>
		/// <param name="param">参数字符串</param>
		/// <returns>响应字符串</returns>
		public String PostString(HttpWebRequest request, String param)
		{
			return  StringFromResponse(Post(request, param), _encoding);
		}

		/// <summary>
		/// POST方式获得响应流
		/// </summary>
		/// <param name="url">请求地址</param>
		/// <param name="param">参数字符串</param>
		/// <returns>响应字符串</returns>
		public String PostString(String url, String param)
		{
			return StringFromResponse(Post(url, param), _encoding);
		}

		/// <summary>
		/// POST方式获得响应流
		/// </summary>
		/// <param name="request">请求对象</param>
		/// <param name="collection">参数集合对象</param>
		/// <returns>响应字符串</returns>
		public String PostString(HttpWebRequest request, NameValueCollection collection)
		{
			return  StringFromResponse(Post(request, collection), _encoding);
		}

		/// <summary>
		/// POST方式获得响应流
		/// </summary>
		/// <param name="url">请求地址</param>
		/// <param name="collection">参数集合对象</param>
		/// <returns>响应字符串</returns>
		public String PostString(String url, NameValueCollection collection)
		{
			return StringFromResponse(Post(url, collection), _encoding);
		}

		/// <summary>
		/// POST方式获得响应流
		/// </summary>
		/// <param name="request">请求对象</param>
		/// <param name="param">参数字符串</param>
		/// <returns>HtmlContext对象</returns>
		public HtmlContext PostHtmlContext(HttpWebRequest request, String param)
		{
			return new HtmlContext(StringFromResponse(Post(request, param), _encoding));
		}

		/// <summary>
		/// POST方式获得响应流
		/// </summary>
		/// <param name="url">请求地址</param>
		/// <param name="param">参数字符串</param>
		/// <returns>HtmlContext对象</returns>
		public HtmlContext PostHtmlContext(String url, String param)
		{
			return new HtmlContext(StringFromResponse(Post(url, param), _encoding));
		}

		/// <summary>
		/// POST方式获得响应流
		/// </summary>
		/// <param name="request">请求对象</param>
		/// <param name="collection">参数集合对象</param>
		/// <returns>HtmlContext对象</returns>
		public HtmlContext PostHtmlContext(HttpWebRequest request, NameValueCollection collection)
		{
			return new HtmlContext(StringFromResponse(Post(request, collection), _encoding));
		}

		/// <summary>
		/// POST方式获得响应流
		/// </summary>
		/// <param name="url">请求地址</param>
		/// <param name="collection">参数集合对象</param>
		/// <returns>HtmlContext对象</returns>
		public HtmlContext PostHtmlContext(String url, NameValueCollection collection)
		{
			return new HtmlContext(StringFromResponse(Post(url, collection), _encoding));
		}

		#endregion

		#region  --静态方法--

		/// <summary>
		/// 从响应中获取内存流
		/// </summary>
		/// <param name="response">响应对象</param>
		/// <returns>内存流</returns>
		public static MemoryStream StreamFromResponse(HttpWebResponse response)
		{
			MemoryStream msr = null;
			try
			{
				//创建流对象，读取响应流，生成字符串
				Stream sr = response.GetResponseStream();
				msr = new MemoryStream();

				byte[] buffer = new byte[1024];
				int count = sr.Read(buffer, 0, 1024);
				while (count > 0)
				{
					msr.Write(buffer, 0, 1024);
					count = sr.Read(buffer, 0, 1024);
				}
			}
			finally
			{
				//关闭响应流
				response.Close();
			}
			return msr;
		}

		/// <summary>
		/// 从响应中获取字符串
		/// </summary>
		/// <param name="response">响应对象</param>
		/// <returns>字符串</returns>
		public static String StringFromResponse(HttpWebResponse response, Encoding encoding)
		{
			StringBuilder returnValue = new StringBuilder();
			try
			{
				//创建流对象，读取响应流，生成字符串
				StreamReader sr = new StreamReader(response.GetResponseStream(), encoding);
				returnValue.Append(sr.ReadToEnd());
			}
			finally
			{
				//关闭响应流
				response.Close();
			}

			//获得并返回响应
			return returnValue.ToString();
		}

		/// <summary>
		/// 将响应保存为文件
		/// </summary>
		/// <param name="response">响应对象</param>
		/// <param name="fileName">文件名（包含路径）</param>
		public static void SaveAsFromResponse(HttpWebResponse response, String fileName)
		{
			Stream sr = null;
			FileStream fs = null;
			try
			{
				//创建流对象
				sr = response.GetResponseStream();
				//创建文件流对象
				fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write);

				//循环读取流保存到文件
				byte[] buffer = new byte[1024];
				int bytesRead = sr.Read(buffer, 0, buffer.Length);
				while (bytesRead > 0)
				{
					fs.Write(buffer, 0, bytesRead);
					bytesRead = sr.Read(buffer, 0, buffer.Length);
				}
			}
			finally
			{
				if (fs != null) fs.Close();
				if (sr != null) sr.Close();
				response.Close();
			}
		}

		#endregion

		#region  --似有方法--

		/// <summary>
		/// 创建参数字符串
		/// </summary>
		/// <param name="paramaters">参数字典</param>
		/// <returns>字符串</returns>
		private static String NameValueCollectionToString(NameValueCollection collection)
		{
			StringBuilder returnValue = new StringBuilder();

			//循环字典，将参数集合转换成字符串
			foreach (String key in collection.Keys)
			{
				returnValue.Append(key);
				returnValue.Append("=");
				returnValue.Append(collection[key]);
				returnValue.Append("&");
			}

			//删除最后一个&连接符号
			if (returnValue.ToString().EndsWith("&", StringComparison.OrdinalIgnoreCase)) returnValue.Remove(returnValue.Length - 1, 1);

			return returnValue.ToString();
		}

		/// <summary>
		/// 设置Post请求参数
		/// </summary>
		/// <param name="request"></param>
		/// <param name="data"></param>
		private void SetPostData(HttpWebRequest request, String data)
		{
			//获取字符串字节值
			byte[] param = _encoding.GetBytes(data);

			//写入请求流
			Stream requestStream = request.GetRequestStream();
			requestStream.Write(param, 0, param.Length);
			requestStream.Close();
		}

		#endregion
	}
}
